/*
 * @Author: 缄默
 * @Date: 2021-12-12 15:16:37
 * @LastEditors: 缄默
 * @LastEditTime: 2021-12-14 16:39:42
 */

//享元模式

#include <iostream>
#include <string>
#include <vector>
#include <map>

using namespace std;

//Flyweight定义时用到UnsharedConcreteFlyweight,所以需要前向声明
class UnsharedConcreteFlyweight;

class Flyweight {
private:
    string _key;
    string _info;
public:
    Flyweight(string key) : _key(key), _info(key) { }
    
    virtual void Operation(UnsharedConcreteFlyweight& unFly) { }

    string GetInfo() const {
        return _info;
    }

    //析构函数最好为虚函数 防止只调用基类析构函数不调用派生类析构函数导致内存析构不完全导致内存泄漏
    virtual ~Flyweight() { }
};

//非共享部分
class UnsharedConcreteFlyweight{
private:
    string _info;
public:
    UnsharedConcreteFlyweight(string info) {
        _info = info;
    }

    void setInfo(string info) {
        _info = info;
    }

    const string& getInfo() {
        return _info;
    }
    void Operation(const string& key) {

    }
};

class ConcreteFlyweight : public Flyweight {
public:
    //注意该写法
    ConcreteFlyweight(string key) : Flyweight(key) {
        cout << "ConcreteFlyweight Build..." << key << endl;
    }

    //共享部分，通过参数传入共享部分呢，结合形成一个整体对象
    void Operation(UnsharedConcreteFlyweight& unFly) {
        cout << "ConcreteFlyweight" << GetInfo() << " \\ " << unFly.getInfo() << endl;
    }
};


//享元工厂 这里可以通过单例模式实现享元工厂
class FlyweightFactory {
private:
    map<string, Flyweight*> _flys;

public:
    Flyweight *GetFlyweight(string key) {
        //相同对象只要保存一份，这降低了系统中对象的数量
        if (_flys.count(key)) {
            return _flys[key];
        }
        Flyweight* fn = new ConcreteFlyweight(key);
        _flys.insert(pair<string, Flyweight*>(key, fn));
        return fn;
    }
};

int main() {
    FlyweightFactory *fc = new FlyweightFactory();
    Flyweight* fw1 = fc->GetFlyweight("hello");
    Flyweight* fw2 = fc->GetFlyweight("world");
    Flyweight* fw3 = fc->GetFlyweight("hello");
    UnsharedConcreteFlyweight* ufw1 = new UnsharedConcreteFlyweight("unshared info 1");
    UnsharedConcreteFlyweight* ufw2 = new UnsharedConcreteFlyweight("unshared info 2");
    fw1->Operation(*ufw1);
    fw2->Operation(*ufw2);
    fw3->Operation(*ufw2);
    
    delete fw1;
    delete fw2;
    delete ufw1;
    delete ufw2;
    delete fc;

    return 0;
}
